#
# P4Custom.py
#
# Custom Menu Implementations for the SNiFF+ 3.x Perforce Adapter
#
# Author: Martin Oberhuber
# Copyright (c) 1998, 1999 TakeFive Software, Salzburg
#
# History:
#    Adapter %VERSION%
#    $Id: P4Custom.py,v 1.5 1999/11/16 14:38:14 mober Exp $

# Standard Modules
import string, os, traceback

# P4 Modules
import P4Prefs, P4Dialogs, P4
import etgui
import vcs
from vcs import SYSTEM, WINDOWS, UNIX, NL, TRUE, FALSE

#----------Constants-----------------------------------------------------
ModMark = "(P4Custom) "

#----------Helper functions----------------------------------------------

def P4Output(RWERoot, PWERoot, PWEName, cmd):
	#cmd = '-p "%s" -c "%s" %s' % (RWERoot, P4Prefs.GetClient(PWERoot, PWEName), cmd)
	return P4.P4Iter(cmd, RWERoot, PWERoot)

def P4Input(RWERoot, PWERoot, PWEName, cmd, form):
	marker = ModMark + "P4Input: "
	fileName = P4Prefs.tmpnam()
	if RWERoot:
		PortArg="-p '%s'" % RWERoot
	else:
		PortArg=""
	if SYSTEM == WINDOWS:
		cmdForm = '''sh -c "p4 %s -c '%s' %s -i < %s"'''
	else:
		cmdForm = "p4 %s -c '%s' %s -i < %s"
	cmd = cmdForm % (PortArg, P4Prefs.GetClient(PWERoot, PWEName), cmd, fileName)
	if P4Prefs.TEST: print marker,"Running ",cmd
	try:
		file = open(fileName,"w")
		file.write(form)
		file.close()
	except IOError:
		import traceback
		traceback.print_exc()
	rc, _out, _err = vcs.RunCmd(cmd)
	if not P4Prefs.TEST: vcs.rm_f(fileName)
	if P4Prefs.TEST: print marker,"Result:",rc, _out
	return rc, _out

def StripRoot(PWERoot, theFiles):
	"""Remove String1 from every entry in String2.
	This function is needed for SNiFF+ below 3.2 in order to
	remove the RepositoryRoot (==P4 client name) from the %A variable."""
	theLen=len(PWERoot)
	## with empty repository & projectDir, RWEFiles will start with a slash!!
	if not theLen: return theFiles
	theResult=""
	for curFile in string.split(theFiles):
		if curFile[:theLen] == PWERoot:
			nextOne = curFile[theLen:] + " "
			try:
				while nextOne[0]=="/" or nextOne[0]=="\\":
					nextOne = nextOne[1:]
			except:
				pass
			if P4Prefs.TEST: print "Stripped |%s| from |%s| = |%s|" % (PWERoot, curFile, curFile[theLen+1:])
			theResult = theResult + nextOne
		else:
			theResult = theResult + curFile + " "
	return theResult

#----------Custom Menu functions-----------------------------------------

def Init(RWERoot, PWERoot, PWEName):
	"""Create an initial mapping from the PWERoot to the Client Name.
	If the WE Name is used to define the P4 Client. This was necessary
	in SNiFF Versions prior to 3.2 because the WE Name was not available 
	to the CMVC Adapter. Since SNiFF 3.2, this function is obsolete."""
	try:
		theClient = P4Prefs.ClientName(PWERoot,PWEName)
		P4Prefs.SetClient(PWERoot, theClient)
	except:
		traceback.print_exc()

def SwitchClient(RWERoot, PWERoot, PWEName):
	"""Switch the P4Client"""
	try:
		# get the current default client
		theClient = P4Prefs.GetClient(PWERoot, PWEName)
		answer = P4Dialogs.AskQuestionDialog("Switch Perforce Client", "New Client name:", theClient)
		if answer:
			if P4Prefs.TEST: print "Perforce: Switching Client to ",answer
			P4Prefs.SetClient(PWERoot, answer)
			if answer != theClient and PWERoot:
				try:
					if P4Prefs.TEST: print "saving in ",PWERoot,"/.p4client"
					open(vcs.joinpath(PWERoot,".p4client"),"w").write(answer+vcs.NL)
				except:
					if P4Prefs.TEST: traceback.print_exc()
					pass
				UpdateLockers("*/")
	except:
		traceback.print_exc()


def DeleteClient(RWERoot, PWERoot, PWEName):
	try:
		theClient = P4Prefs.GetClient(PWERoot, PWEName)
		answer=P4Dialogs.askYesNo("Delete Client", "Are you sure you want to delete your client specification for "+theClient+"?")
		if answer:
			p4=P4.P4Iter("client -d "+theClient, RWERoot, PWERoot)
			print string.join(p4.lines,NL)
			UpdateLockers("*/")
	except:
		traceback.print_exc()

def P4Client(RWERoot, PWERoot, PWEName):
	try:
		marker = ModMark + "P4Client: "
		clientName = P4Prefs.GetClient(PWERoot, PWEName)
		P4Prefs.SetClient(PWERoot, clientName)
		if P4Prefs.TEST: print marker, "RWERoot: ",RWERoot, ", PWEName: ",PWEName
		P4 = P4Output(RWERoot, PWERoot, PWEName, "-d %s client -o" % PWERoot)
		form = P4Dialogs.P4GenDialog("Edit Client Specification", P4.lines, [ "Client", "Update", "Access" ])
		if form:
			(rc,_out) = P4Input(RWERoot, PWERoot, PWEName, "client", form)
			if P4Prefs.TEST: print marker,"Output of Client Setting: ",_out
			UpdateLockers("*/")
	except:
		traceback.print_exc()

def P4Submit(RWERoot, PWERoot, PWEName, Username, theFile="", SniffAccessProject=""):
	try:
		marker = ModMark + "P4Submit: "
		if P4Prefs.TEST: print marker, "RWERoot: ",RWERoot, ", PWEName: ",PWEName
		ClientName = P4Prefs.GetClient(PWERoot, PWEName)
		if theFile:
			# called from the Editor!
			DoSniffAccess(SniffAccessProject, theFile, "save_file")
		P4 = P4Output(RWERoot, PWERoot, PWEName, "opened")
		if P4Prefs.TEST2: print P4.lines
		if not P4.lines or not P4.lines[0] or string.find(P4.lines[0],"not opened")>0:
			P4Dialogs.ErrorDialog("You have currently no files opened for submit in client %s" % ClientName, "(Submit) Error")
			return 0
#### attention: pre-formatted Perforce form
#### Do not modify following code, every tab is needed ;-)
		form = """Change:	new

Client:	""" + ClientName + """

Status:	new

Description:
	

Files:
"""
### End of pre-formatted Perforce form
		for curLine in P4.lines:
			form = form + "\t" + curLine + NL
		(model, FieldList, BigFields) = P4Dialogs.P4ModelFromForm(string.split(form,NL))
		DialogOk = 0
		while not DialogOk:
			res = P4Dialogs.P4ShowDialog("Submit", model, FieldList, BigFields, ["Change", "Date", "Client", "User", "Status"])
			if not res:
				return 0
			if not string.strip(model.GetValue("Description")):
				P4Dialogs.ErrorDialog("You must enter a Description for submitting!", "(Submit) Error")
			else:
				DialogOk=1
		form = P4Dialogs.P4FormFromModel(model, FieldList, BigFields)
		(rc,_out) = P4Input(RWERoot, PWERoot, PWEName, "submit", form)
		print "Perforce Submit Output: ",_out
		UpdateLockers("*/", "update_file_info")
		if theFile:
			# called from the Editor: submit may have changed keywords!
			DoSniffAccess(SniffAccessProject, theFile, "edit_file")
		return rc
	except:
		traceback.print_exc()

def ChooseFiletype(theTitle, theFiles):
	theText = ""
	for curName in string.split(theFiles):
		(dir,name)=os.path.split(curName)
		if not theText:
			theText="Please select a Perforce Filetype for @B"+name+"@B, "
			lineLen=len(theText)-4
		elif len(theText)>300:
			theText = theText+"..."
			break
		else:
			theText = theText+"@B"+name+"@B, "
			lineLen=lineLen + len(name)
			if lineLen > 60: 
				theText = theText + vcs.NL
				lineLen=0
	if not lineLen:
		theText=theText[:-3]
	else:
		theText=theText[:-2]
	fileTypes=["text", "ktext", "xtext", "kxtext", "binary", "xbinary", "other..."]
	rv=P4Dialogs.ChoiceDialog(theTitle, theText, fileTypes, P4Prefs.DefaultFiletype)
	if rv:
		while rv=="other...":
			rv = P4Dialogs.AskQuestionDialog(theTitle, "Select special Filetype:", "text+xwkCDFS")
		if rv:
			P4Prefs.DefaultFiletype=rv
	return rv

def DoSniffAccess(SniffAccessProjects, theFiles, theCommand):
	try:
		if len(string.split(SniffAccessProjects)) > 1: SniffAccessProjects="*/"
		for curFile in string.split(theFiles):
			(dir,file)=os.path.split(curFile)
			etgui.Sniffaccess(theCommand, SniffAccessProjects, file)
	except:
		pass

def UpdateLockers(SniffAccessProjects,updateCommand=""):
	try:
		# first of all, invalidate the global lockers cache to make sure info is re-read 
		# from perforce. Invalidating everything is not very efficient, but it is safe...
		P4.InvalidateLockersCache()
		for curProject in string.split(SniffAccessProjects):
			if updateCommand:
				if P4Prefs.TEST: print "Calling sniffaccess ",updateCommand, " ",curProject
				etgui.Sniffaccess(updateCommand, curProject)
			if P4Prefs.TEST: print "Calling sniffaccess update_lockers ",curProject
			etgui.Sniffaccess("update_lockers", curProject)
	except:
		# exception during update lockers is non-fatal!
		pass

def P4Sync(RWERoot, PWERoot, PWEName, SniffAccessProjects, theFiles, isEditor=0):
	try:
		theFiles=StripRoot(RWERoot,theFiles)
		if isEditor:
			DoSniffAccess(SniffAccessProjects, theFiles, "save_file")
		p4=P4.P4Iter("-d %s sync %s" % (PWERoot, theFiles), RWERoot, PWERoot, PWEName)
		print "@Bp4 sync results@B:" + string.join(p4.lines,vcs.NL)
		UpdateLockers(SniffAccessProjects,"update_file_info")
		if isEditor:
			DoSniffAccess(SniffAccessProjects, theFiles, "edit_file")
	except:
		traceback.print_exc()

def P4Add(RWERoot, PWERoot, PWEName, SniffAccessProjects, theFiles, isEditor=0):
	try:
		if isEditor:
			DoSniffAccess(SniffAccessProjects, theFiles, "save_file")
		theFiles=StripRoot(RWERoot,theFiles)
		p4=P4.P4Iter("-d %s add %s" % (PWERoot, theFiles), RWERoot, PWERoot, PWEName)
		print "@Bp4 add results@B:" + string.join(p4.lines,vcs.NL)
		UpdateLockers(SniffAccessProjects)
	except:
		traceback.print_exc()

def P4Edit(RWERoot, PWERoot, PWEName, SniffAccessProjects, theFiles, isEditor=0):
	try:
		theFiles=StripRoot(RWERoot,theFiles)
		p4=P4.P4Iter("-d %s edit %s" % (PWERoot, theFiles), RWERoot, PWERoot, PWEName)
		print "@Bp4 edit results@B:" + string.join(p4.lines,vcs.NL)
		print "@rNote:@r @BFile -> Check Out@B will sync selected files to HEAD and edit them in one step!"
		UpdateLockers(SniffAccessProjects,"update_file_info")
		if isEditor:
			DoSniffAccess(SniffAccessProjects, theFiles, "edit_file")
	except:
		traceback.print_exc()

def P4Revert(RWERoot, PWERoot, PWEName, SniffAccessProjects, theFiles, isEditor=0):
	try:
		answer=P4Dialogs.askYesNo("Revert", "Reverting file(s) will overwrite any edits to the file(s)\n Proceed with Revert?")
		theFiles=StripRoot(RWERoot,theFiles)
		if answer:
			if isEditor:
				# first save modified contents to avoid ugly dialog
				DoSniffAccess(SniffAccessProjects, theFiles, "save_file")
			p4=P4.P4Iter("-d %s revert %s" % (PWERoot, theFiles), RWERoot, PWERoot, PWEName)
			# BUGBUG--delete files if they are now the same as in the SSWE,
			# like synchronize does?
			UpdateLockers(SniffAccessProjects,"update_file_info")
			if isEditor:
				DoSniffAccess(SniffAccessProjects, theFiles, "edit_file")
	except:
		traceback.print_exc()

def P4Delete(RWERoot, PWERoot, PWEName, SniffAccessProjects, theFiles):
	try:
		theFiles=StripRoot(RWERoot,theFiles)
		p4=P4.P4Iter("-d %s delete %s" % (PWERoot, theFiles), RWERoot, PWERoot, PWEName)
		#P4Dialogs.ErrorDialog("p4 delete results:\n"+string.join(p4.lines,vcs.NL),"p4 delete results",0)
		print "@Bp4 delete results@B:" + string.join(p4.lines,vcs.NL)
		UpdateLockers(SniffAccessProjects)
		print "Don't forget to also remove deleted files from your SNiFF projects before you commit!"
	except:
		traceback.print_exc()

def P4Have(RWERoot, PWERoot, PWEName):
	try:
		p4=P4.P4Iter("have ", RWERoot, PWERoot, PWEName)
		P4Dialogs.AskQuestionDialog("p4 have results", "p4 have results:", string.join(p4.lines,NL), 1)
	except:
		traceback.print_exc()

def P4Opened(RWERoot, PWERoot, PWEName):
	try:
		p4=P4.P4Iter("opened ", RWERoot, PWERoot, PWEName)
		P4Dialogs.AskQuestionDialog("p4 opened results", "p4 opened results:", string.join(p4.lines,NL), 1)
	except:
		traceback.print_exc()

def P4ChangeFiletype(RWERoot, PWERoot, PWEName, SniffAccessProjects, theFiles):
	"""Change the Filetype for a list of files. Don't currently need to
	update the lockers because this info is currently not displayed."""
	try:
		theType = ChooseFiletype("Change Perforce Filetype", theFiles)
		if theType:
			p4=P4.P4Iter("reopen -t %s %s" % (theType, theFiles), RWERoot, PWERoot, PWEName)
			UpdateLockers(SniffAccessProjects)
			P4Dialogs.ErrorDialog("p4 reopen results:\n"+string.join(p4.lines,NL),"p4 reopen results",0)
	except:
		traceback.print_exc()

def P4Describe(RWERoot, PWERoot, PWEName, SniffAccessProject):
	try:
		theChangelists = P4Dialogs.AskQuestionDialog("p4 describe", "Enter Changelist numbers:")
		if theChangelists:
			p4=P4.P4Iter("describe -s %s" % theChangelists, RWERoot, PWERoot, PWEName)
			#BUGBUG better exec in the shell or print to the log tool to keep it available?
			#P4Dialogs.ErrorDialog("p4 describe results:\n"+string.join(p4.lines,NL),"p4 describe results",0)
			P4Dialogs.AskQuestionDialog("p4 describe results", "p4 describe results:", string.join(p4.lines,NL),1)
	except:
		traceback.print_exc()

def P4Jobs(RWERoot, PWERoot, PWEName, SniffAccessProject):
	try:
		p4=P4.P4Iter("jobs", RWERoot, PWERoot, PWEName)
		#BUGBUG better exec in the shell or print to the log tool to keep it available?
		#P4Dialogs.ErrorDialog("p4 jobs results:\n"+string.join(p4.lines,NL),"p4 jobs results",0)
		P4Dialogs.AskQuestionDialog("p4 jobs results", "p4 jobs results:", string.join(p4.lines,NL),1)
	except:
		traceback.print_exc()

def P4Resolve(RWERoot, PWERoot, PWEName, SniffAccessProject):
	try:
		#BUGBUG must exec per sniffaccess in the shell because it's 
		#interactive!
		theClient=P4Prefs.GetClient(PWERoot,PWEName)
		if RWERoot:
			PortArg = "-p %s" % RWERoot
		else:
			PortArg = ""
		cmd="p4 %s -c %s resolve" % (PortArg, theClient)
		etgui.Sniffaccess("shell",SniffAccessProject,"""'%s'""" % cmd)
	except:
		traceback.print_exc()

def ToggleVersionDisplay():
	try:
		P4Prefs.LockersShowVersion = 1 - P4Prefs.LockersShowVersion
		print "Lockers Version Display is now ",P4Prefs.LockersShowVersion
		print "If Display doesn't change immediately switch lockers column off and on again."
		UpdateLockers("*/")
	except:
		traceback.print_exc()

def ToggleFiletypeDisplay():
	try:
		P4Prefs.LockersShowFiletype = 1 - P4Prefs.LockersShowFiletype
		print "Lockers Filetype Display is now ",P4Prefs.LockersShowFiletype
		print "If Display doesn't change immediately switch lockers column off and on again."
		UpdateLockers("*/")
	except:
		traceback.print_exc()

def ToggleBranchDisplay():
	try:
		P4Prefs.LockersShowBranch = 1 - P4Prefs.LockersShowBranch
		print "Lockers Branch Display is now ",P4Prefs.LockersShowBranch
		print "If Display doesn't change immediately switch lockers column off and on again."
		UpdateLockers("*/")
	except:
		traceback.print_exc()

def ToggleVCSDebug():
	try:
		try:
			vcs.TEST=1-vcs.TEST
		except:
			vcs.TEST=1
		print 'VCS Debugging is now ',vcs.TEST
	except:
		traceback.print_exc()

def ToggleP4Debug():
	try:
		try:
			P4Prefs.TEST=1-P4Prefs.TEST
		except:
			P4Prefs.TEST=1
		print 'P4 Adaptor: Debugging is now ',P4Prefs.TEST
	except:
		traceback.print_exc()

#----------Tests----------------------------------------------------------

if __name__ == '__main__':
	#P4Client("perforce:1666", "/sapmnt/home1/d000723/WS/BIN/src", "d000723 PWE:da1218_d000723")
	#P4Submit("perforce:1666", "/sapmnt/home1/d000723/WS/BIN/src", "d000723 PWE:da1218_d000723", "d000723")
	print ModMark, "No Test"



